//using System;
//using System.Collections.Generic;
//using System.Collections.ObjectModel;
//using System.ComponentModel;
//using System.IO;
//using Microsoft.Xna.Framework;
//using Microsoft.Xna.Framework.Content.Pipeline;
//using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
//using Microsoft.Xna.Framework.Content.Pipeline.Processors;
//using Microsoft.Xna.Framework.Graphics;
//using Microsoft.Xna.Framework.Graphics.PackedVector;
//using ShevaEngine.Core.Modules.Animations;
//using ShevaEngine.Core.Modules.Models;
//using ShevaEngine2ContentPipeline.Common;
//using ShevaEngine2ContentPipeline.Common.ModelSplit;

//namespace ShevaContentPipeline.Processors.AnimatedModels
//{
//    /// <summary>
//    /// Processes a NodeContent object that was imported by SkinnedModelImporter
//    /// and attaches animation data to its tag
//    /// </summary>
//    [ContentProcessor(DisplayName = "ShevaModelProcessorOld")]
//    public class ShevaModelProcessorOld : ContentProcessor<NodeContent, ShevaInternalModel>
//    {
//        private BoneIndexer[] indexers = null;
//        List<Matrix> absoluteMeshTransforms = null;
//        /// <summary>Buffers.</summary>
//        private List<ModelInternalBuffer> Buffers;
//        /// <summary>VertexDeclaration to Buffer map.</summary>
//        public Dictionary<VertexDeclarationContent, int> VDBuffers;
//        /// <summary>Scale.</summary>
//        [DefaultValue(1.0f)]
//        public Single Scale { get; set; }

//        public ShevaModelProcessorOld()
//        {
//            this.Scale = 1.0f;
//        }

//        /// <summary>Processes a SkinnedModelImporter NodeContent root</summary>
//        /// <param name="input">The root of the X file tree</param>
//        /// <param name="context">The context for this processor</param>
//        /// <returns>A model with animation data on its tag</returns>
//        public override ShevaInternalModel Process(NodeContent input, ContentProcessorContext context)
//        {
//            MeshHelper.TransformScene(input, Matrix.CreateScale(this.Scale));

//            ShevaInternalModel output = new ShevaInternalModel();

//            this.Buffers = new List<ModelInternalBuffer>();
//            this.VDBuffers = new Dictionary<VertexDeclarationContent, int>(new VertexDeclarationEqualityComparer());

//            ModelSplitter splitter;

//            if (context.TargetPlatform != TargetPlatform.Xbox360)
//                splitter = new ModelSplitter(input, 50);
//            else
//                splitter = new ModelSplitter(input, 40);

//            bool modelSplit = splitter.Split();

//            output.Meshes = this.FindMeshes(input);

//            output.Buffers = this.Buffers;

//            this.indexers = new BoneIndexer[output.Meshes.Length];

//            for (int i = 0; i < indexers.Length; i++)
//            {
//                this.indexers[i] = new BoneIndexer();
//            }



//            // Get the process model minus the animation data
//            //ModelProcessor modelProcessor = new ModelProcessor();
//            //modelProcessor.ColorKeyEnabled = false;
//            //modelProcessor.GenerateMipmaps = false;
//            //modelProcessor.GenerateTangentFrames = false;

//            //ModelContent c = modelProcessor.Process(input, context);

//            //if (!modelSplit && input.OpaqueData.ContainsKey("AbsoluteMeshTransforms"))
//            //    absoluteMeshTransforms = (List<Matrix>)input.OpaqueData["AbsoluteMeshTransforms"];
//            //else
//            //    foreach (MeshContent mesh in meshes)
//            //    {
//            //        if (!this.ValidateMeshSkeleton(mesh))
//            //        {
//            //            context.Logger.LogWarning(null, mesh.Identity, "Warning: Mesh found that has a parent that exists as "
//            //                + "one of the bones in the skeleton attached to the mesh.  Change the mesh "
//            //                + "skeleton structure or use X - File Animation Library importer if transforms are incorrect.");
//            //        }
//            //    }


//            Dictionary<string, AnimationContent> animations = this.FindAnimations(input);

//            // Test to see if any animations have zero duration
//            foreach (AnimationContent anim in animations.Values)
//            {
//                string errorMsg = "One or more AnimationContent objects have an extremely small duration.  If the animation "
//                        + "was intended to last more than one frame, please add \n AnimTicksPerSecond \n{0} \nY; \n{1}\n to your .X "
//                        + "file, where Y is a positive integer.";
//                if (anim.Duration.Ticks < ContentUtil.TICKS_PER_60FPS)
//                {
//                    context.Logger.LogWarning("", anim.Identity, errorMsg, "{", "}");

//                    break;
//                }
//            }


//            try
//            {
//                AnimationInfoCollection processedAnims = new AnimationInfoCollection();

//                foreach (KeyValuePair<string, AnimationContent> animKey in animations)
//                    processedAnims.Add(this.Interpolate(animKey.Value));

//                output.Animations = processedAnims;
//            }
//            catch
//            {
//                throw new Exception("Error processing animations.");
//            }

//            //output.SkinInfo = this.ProcessSkinInfo(input);

//            return output;
//        }


//        /// <summary>
//        /// Metoda nalezne parametry modelu.
//        /// </summary>
//        /// <param name="node"></param>
//        private ShevaInternalMesh[] FindMeshes(NodeContent node)
//        {
//            List<ShevaInternalMesh> output = new List<ShevaInternalMesh>();

//            Queue<NodeContent> nodes = new Queue<NodeContent>();
//            nodes.Enqueue(node);

//            while (nodes.Count > 0)
//            {
//                NodeContent actualNodeContent = nodes.Dequeue();

//                if (actualNodeContent is MeshContent)
//                {
//                    //MeshHelper.SwapWindingOrder(actualNodeContent as MeshContent);
//                    //MeshHelper.CalculateNormals(actualNodeContent as MeshContent, true);                    

//                    if ((actualNodeContent as MeshContent).Geometry[0].Vertices.Channels.Contains("TextureCoordinate0") &&
//                        !(actualNodeContent as MeshContent).Geometry[0].Vertices.Channels.Contains("Tangent0"))
//                        MeshHelper.CalculateTangentFrames(actualNodeContent as MeshContent,
//                        VertexChannelNames.TextureCoordinate(0),
//                        VertexChannelNames.Tangent(0),
//                        VertexChannelNames.Binormal(0));

//                    ShevaInternalMesh newMesh = new ShevaInternalMesh();

//                    newMesh.Transform = ((MeshContent)actualNodeContent).Transform;

//                    //mesh.OpaqueData.Add("MeshIndex", output.Count);

//                    newMesh.Geometries = this.GetGeometries((MeshContent)actualNodeContent);

//                    output.Add(newMesh);
//                }

//                foreach (NodeContent child in actualNodeContent.Children)
//                    nodes.Enqueue(child);
//            }

//            return output.ToArray();
//        }

//        /// <summary>
//        /// Metoda ziska geometrie.
//        /// </summary>
//        /// <param name="mesh"></param>
//        /// <returns></returns>
//        private ShevaInternalModelGeometry[] GetGeometries(MeshContent mesh)
//        {
//            List<ShevaInternalModelGeometry> geometries = new List<ShevaInternalModelGeometry>();

//            foreach (GeometryContent meshPart in mesh.Geometry)
//            {
//                if (meshPart.Indices.Count != 0)
//                {
//                    ShevaInternalModelGeometry newGeometry = new ShevaInternalModelGeometry();

//                    newGeometry.MaterialParameters = new ModelMaterialParameters();

//                    if (meshPart.Material != null)
//                    {
//                        try
//                        {
//                            newGeometry.MaterialParameters.Name = meshPart.Material.Name.Split('_')[0];
//                        }
//                        catch
//                        {
//                            newGeometry.MaterialParameters.Name = "Default";
//                        }

//                        //newGeometry.MaterialParameters.Name = meshPart.Material.OpaqueData.GetContentAsXml();

//                        foreach (string key in meshPart.Material.OpaqueData.Keys)
//                            switch (key)
//                            {
//                                case "Name":
//                                    newGeometry.MaterialParameters.Name = (string)meshPart.Material.OpaqueData[key];
//                                    break;
//                                case "DiffuseColor":
//                                    newGeometry.MaterialParameters.Diffuse = new Color((Vector3)meshPart.Material.OpaqueData[key]);
//                                    break;
//                                case "EmissiveColor":
//                                    newGeometry.MaterialParameters.Emissive = new Color((Vector3)meshPart.Material.OpaqueData[key]);
//                                    break;
//                                case "SpecularColor":
//                                    newGeometry.MaterialParameters.Specular = new Color((Vector3)meshPart.Material.OpaqueData[key]);
//                                    break;
//                                case "SpecularPower":
//                                    newGeometry.MaterialParameters.SpecularPower = (float)meshPart.Material.OpaqueData[key];
//                                    break;
//                                case "Alpha":
//                                    newGeometry.MaterialParameters.Alpha = (float)meshPart.Material.OpaqueData[key];
//                                    break;
//                                default:
//                                    break;
//                            }

//                        foreach (KeyValuePair<string, ExternalReference<TextureContent>> item in meshPart.Material.Textures)
//                        {
//                            //newGeometry.MaterialParameters.TexturesTemp.Add(item.Key, Path.GetFileNameWithoutExtension(item.Value.Filename));

//                            switch (item.Key)
//                            {
//                                case "Texture":
//                                    newGeometry.MaterialParameters.TexturesTemp.Add("Diffuse", Path.GetFileNameWithoutExtension(item.Value.Filename));
//                                    break;
//                                case "SpecularFactor":
//                                    newGeometry.MaterialParameters.TexturesTemp.Add("Specular", Path.GetFileNameWithoutExtension(item.Value.Filename));
//                                    break;
//                                case "Reflection":
//                                    //newGeometry.MaterialParameters.TexturesTemp.Add("Reflection", Path.GetFileNameWithoutExtension(item.Value.Filename));
//                                    break;
//                                case "Bump":
//                                    newGeometry.MaterialParameters.TexturesTemp.Add("Normal", Path.GetFileNameWithoutExtension(item.Value.Filename));
//                                    break;
//                                case "Transparency":
//                                    break;
//                                default:
//                                    break;
//                            }
//                        }
//                    }

//                    //int meshIndex = (int)mesh.OpaqueData["MeshIndex"];

//                    //BoneIndexer indexer = indexers[meshIndex];

//                    //foreach (VertexChannel channel in meshPart.Vertices.Channels)
//                    //    if (channel.Name == VertexChannelNames.Weights())
//                    //    {
//                    //        VertexChannel<BoneWeightCollection> vc = (VertexChannel<BoneWeightCollection>)channel;

//                    //        foreach (BoneWeightCollection boneWeights in vc)
//                    //            foreach (BoneWeight weight in boneWeights)
//                    //                indexer.GetBoneIndex(weight.BoneName);                        
//                    //    }

//                    newGeometry.NumVertices = meshPart.Vertices.VertexCount;
//                    newGeometry.PrimitiveCount = meshPart.Indices.Count / 3;
//                    newGeometry.PrimitiveType = PrimitiveType.TriangleList;

//                    //VertexBufferContent VBOContent = meshPart.Vertices.CreateVertexBuffer();
//                    //newGeometry.VertexElements = new List<VertexElement>(VBOContent.VertexDeclaration.VertexElements).ToArray();
//                    //newGeometry.VertexStride = (int)VBOContent.VertexDeclaration.VertexStride;
//                    //newGeometry.VBO = VBOContent.VertexData;

//                    //newGeometry.IBO = new List<Int32>(meshPart.Indices);

//                    //for (int i = 0; i < meshPart.Vertices.VertexCount; i++)
//                    //{
//                    //    Vector3 temp = meshPart.Vertices.Positions[i];

//                    //    temp.X = Vector3.Transform(meshPart.Vertices.Positions[i], this.ScaleMatrix).X;
//                    //    temp.Y = Vector3.Transform(meshPart.Vertices.Positions[i], this.ScaleMatrix).Y;
//                    //    temp.Z = Vector3.Transform(meshPart.Vertices.Positions[i], this.ScaleMatrix).Z;

//                    //    meshPart.Vertices.Positions[i] = temp;
//                    //}                                       

//                    VertexBufferContent vboContent = meshPart.Vertices.CreateVertexBuffer();

//                    VertexElement[] elements = new VertexElement[vboContent.VertexDeclaration.VertexElements.Count];
//                    for (int i = 0; i < vboContent.VertexDeclaration.VertexElements.Count; i++)
//                        elements[i] = vboContent.VertexDeclaration.VertexElements[i];

//                    if (!this.VDBuffers.ContainsKey(vboContent.VertexDeclaration))
//                    {
//                        this.VDBuffers.Add(vboContent.VertexDeclaration, this.VDBuffers.Count);
//                        this.Buffers.Add(new ModelInternalBuffer());
//                        this.Buffers[this.Buffers.Count - 1].VertexElements = elements;
//                        this.Buffers[this.Buffers.Count - 1].ElementSize = IndexElementSize.ThirtyTwoBits;
//                        this.Buffers[this.Buffers.Count - 1].VertexStride = vboContent.VertexDeclaration.VertexStride;
//                    }

//                    newGeometry.BuffersIndex = this.VDBuffers[vboContent.VertexDeclaration];

//                    newGeometry.BaseVertex = this.Buffers[newGeometry.BuffersIndex].VerticesCount;

//                    this.Buffers[newGeometry.BuffersIndex].VerticesCount += meshPart.Vertices.VertexCount;
//                    this.Buffers[newGeometry.BuffersIndex].VertexBufferContent.AddRange(vboContent.VertexData);

//                    newGeometry.StartIndex = this.Buffers[newGeometry.BuffersIndex].IndicesCount;

//                    foreach (int item in meshPart.Indices)
//                        this.Buffers[newGeometry.BuffersIndex].IndexBufferContent.AddRange(BitConverter.GetBytes((int)item));

//                    this.Buffers[newGeometry.BuffersIndex].IndicesCount += meshPart.Indices.Count;

//                    Vector3 min = new Vector3(float.MaxValue);
//                    Vector3 max = new Vector3(float.MinValue);

//                    foreach (Vector3 vertex in meshPart.Vertices.Positions)
//                    {
//                        Vector3 temp = Vector3.Transform(vertex, meshPart.Parent.AbsoluteTransform);

//                        min.X = Math.Min(min.X, temp.X);
//                        min.Y = Math.Min(min.Y, temp.Y);
//                        min.Z = Math.Min(min.Z, temp.Z);

//                        max.X = Math.Max(max.X, temp.X);
//                        max.Y = Math.Max(max.Y, temp.Y);
//                        max.Z = Math.Max(max.Z, temp.Z);
//                    }

//                    newGeometry.BoundingBox = new BoundingBox(min, max);

//                    geometries.Add(newGeometry);
//                }
//            }

//            return geometries.ToArray();
//        }

//        /// <summary>
//        /// Metoda vrati bounding box.
//        /// </summary>
//        /// <param name="model"></param>
//        /// <returns></returns>
//        //        public BoundingBox GetBoundingBoxFromModel(ShevaModel model)
//        //{
//        //  BoundingBox boundingBox = new BoundingBox()


//        //  foreach (ShevaMesh mesh in model.Meshes)
//        //  {
//        //    VertexPositionNormalTexture[] vertices =
//        //      new VertexPositionNormalTexture[mesh.VertexBuffer.SizeInBytes / VertexPositionNormalTexture.SizeInBytes];

//        //    mesh.VertexBuffer.GetData<VertexPositionNormalTexture>(vertices);

//        //    Vector3[] vertexs = new Vector3[vertices.Length];

//        //    for (int index = 0; index < vertexs.Length; index++)
//        //    {
//        //      vertexs[index] = vertices[index].Position;
//        //    }

//        //    boundingBox = BoundingBox.CreateMerged(boundingBox,
//        //      BoundingBox.CreateFromPoints(vertexs));
//        //  }

//        //  return boundingBox;
//        //        }

//        // returns true if the model contains meshes that have a parent bone as a child of 
//        // a bone in the skeleton attached to the mesh.
//        private bool ValidateMeshSkeleton(MeshContent meshContent)
//        {
//            List<string> meshParentHierarchy = new List<string>();
//            int meshIndex = (int)meshContent.OpaqueData["MeshIndex"];
//            BoneIndexer indexer = indexers[meshIndex];
//            if (indexer.SkinnedBoneNames.Contains(meshContent.Parent.Name))
//            {
//                // Warning
//                return false;
//            }
//            // skeleton is fine
//            return true;

//        }


//        private void CalculateAbsoluteTransforms(ModelBoneContent bone, Matrix[] transforms)
//        {
//            if (bone.Parent == null)
//                transforms[bone.Index] = bone.Transform;
//            else
//            {
//                transforms[bone.Index] = bone.Transform * transforms[bone.Parent.Index];
//            }
//            foreach (ModelBoneContent child in bone.Children)
//                CalculateAbsoluteTransforms(child, transforms);
//        }


//        /// <summary>
//        /// Metoda nacte informace o skinu.
//        /// </summary>
//        /// <param name="model"></param>
//        /// <returns></returns>
//        private SkinInfoCollection[] ProcessSkinInfo(ModelContent model)
//        {
//            SkinInfoCollection[] info = new SkinInfoCollection[model.Meshes.Count];
//            Dictionary<string, int> boneDict = new Dictionary<string, int>();

//            foreach (ModelBoneContent b in model.Bones)
//                if (b.Name != null && !boneDict.ContainsKey(b.Name))
//                    boneDict.Add(b.Name, b.Index);

//            for (int i = 0; i < info.Length; i++)
//            {
//                info[i] = new SkinInfoCollection();

//                BoneIndexer indexer = indexers[i];
//                ReadOnlyCollection<string> skinnedBoneNames = indexer.SkinnedBoneNames;

//                Matrix[] absoluteTransforms = new Matrix[model.Bones.Count];
//                CalculateAbsoluteTransforms(model.Bones[0], absoluteTransforms);

//                Matrix absoluteMeshTransform;

//                if (absoluteMeshTransforms == null)
//                    absoluteMeshTransform = absoluteTransforms[model.Meshes[i].ParentBone.Index];
//                else
//                    absoluteMeshTransform = absoluteMeshTransforms[i];

//                for (int j = 0; j < skinnedBoneNames.Count; j++)
//                {
//                    string name = skinnedBoneNames[j];

//                    info[i].Add(new SkinInfo(
//                        name,
//                        absoluteMeshTransform * Matrix.Invert(absoluteTransforms[boneDict[name]]),
//                        indexer.GetBoneIndex(name),
//                        boneDict[name]));
//                }
//            }

//            return info;
//        }

//        /// <summary>
//        /// Searches through the NodeContent tree for all animations and puts them in
//        /// one AnimationContentDictionary
//        /// </summary>
//        /// <param name="node">The root of the tree</param>
//        private Dictionary<string, AnimationContent> FindAnimations(NodeContent node)
//        {
//            Dictionary<string, AnimationContent> output = new Dictionary<string, AnimationContent>();

//            Queue<NodeContent> nodes = new Queue<NodeContent>();

//            nodes.Enqueue(node);

//            while (nodes.Count > 0)
//            {
//                NodeContent actualContent = nodes.Dequeue();

//                foreach (KeyValuePair<string, AnimationContent> k in actualContent.Animations)
//                {
//                    if (output.ContainsKey(k.Key))
//                        foreach (KeyValuePair<string, AnimationChannel> c in k.Value.Channels)
//                            output[k.Key].Channels.Add(c.Key, c.Value);
//                    else
//                        output.Add(k.Key, k.Value);
//                }

//                foreach (NodeContent child in actualContent.Children)
//                    nodes.Enqueue(child);
//            }

//            return output;
//        }

//        /// <summary>
//        /// Go through the vertex channels in the geometry and replace the 
//        /// BoneWeightCollection objects with weight and index channels.
//        /// </summary>
//        /// <param name="geometry">The geometry to process.</param>
//        /// <param name="vertexChannelIndex">The index of the vertex channel to process.</param>
//        /// <param name="context">The processor context.</param>
//        protected void ProcessVertexChannel(GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context)
//        {
//            bool boneCollectionsWithZeroWeights = false;

//            if (geometry.Vertices.Channels[vertexChannelIndex].Name == VertexChannelNames.Weights())
//            {
//                int meshIndex = (int)geometry.Parent.OpaqueData["MeshIndex"];
//                BoneIndexer indexer = indexers[meshIndex];
//                // Skin channels are passed in from importers as BoneWeightCollection objects
//                VertexChannel<BoneWeightCollection> vc =
//                    (VertexChannel<BoneWeightCollection>)
//                    geometry.Vertices.Channels[vertexChannelIndex];
//                int maxBonesPerVertex = 0;
//                for (int i = 0; i < vc.Count; i++)
//                {
//                    int count = vc[i].Count;
//                    if (count > maxBonesPerVertex)
//                        maxBonesPerVertex = count;
//                }

//                // Add weights as colors (Converts well to 4 floats)
//                // and indices as packed 4byte vectors.
//                Color[] weightsToAdd = new Color[vc.Count];
//                Byte4[] indicesToAdd = new Byte4[vc.Count];

//                // Go through the BoneWeightCollections and create a new
//                // weightsToAdd and indicesToAdd array for each BoneWeightCollection.
//                for (int i = 0; i < vc.Count; i++)
//                {

//                    BoneWeightCollection bwc = vc[i];

//                    if (bwc.Count == 0)
//                    {
//                        boneCollectionsWithZeroWeights = true;
//                        continue;
//                    }

//                    bwc.NormalizeWeights(4);
//                    int count = bwc.Count;
//                    if (count > maxBonesPerVertex)
//                        maxBonesPerVertex = count;

//                    // Add the appropriate bone indices based on the bone names in the
//                    // BoneWeightCollection
//                    Vector4 bi = new Vector4();
//                    bi.X = count > 0 ? indexer.GetBoneIndex(bwc[0].BoneName) : (byte)0;
//                    bi.Y = count > 1 ? indexer.GetBoneIndex(bwc[1].BoneName) : (byte)0;
//                    bi.Z = count > 2 ? indexer.GetBoneIndex(bwc[2].BoneName) : (byte)0;
//                    bi.W = count > 3 ? indexer.GetBoneIndex(bwc[3].BoneName) : (byte)0;


//                    indicesToAdd[i] = new Byte4(bi);
//                    Vector4 bw = new Vector4();
//                    bw.X = count > 0 ? bwc[0].Weight : 0;
//                    bw.Y = count > 1 ? bwc[1].Weight : 0;
//                    bw.Z = count > 2 ? bwc[2].Weight : 0;
//                    bw.W = count > 3 ? bwc[3].Weight : 0;
//                    weightsToAdd[i] = new Color(bw);
//                }

//                // Remove the old BoneWeightCollection channel
//                geometry.Vertices.Channels.Remove(vc);
//                // Add the new channels
//                geometry.Vertices.Channels.Add<Byte4>("BlendIndices0", indicesToAdd);
//                geometry.Vertices.Channels.Add<Color>("BlendWeight0", weightsToAdd);
//            }

//            if (boneCollectionsWithZeroWeights)
//                context.Logger.LogWarning("", geometry.Identity,
//                    "BonesWeightCollections with zero weights found in geometry.");
//        }


//        /// <summary>
//        /// Interpolates all the AnimationContent in the specified dictionary to 60 fps.
//        /// </summary>
//        /// <param name="input">The animation dictionary to interpolate.</param>
//        /// <returns>An interpolated dictionary of animations.</returns>
//        public virtual AnimationInfoCollection Interpolate(AnimationContentDictionary input)
//        {
//            AnimationInfoCollection output = new AnimationInfoCollection();

//            foreach (string name in input.Keys)
//                output.Add(this.Interpolate(input[name]));

//            return output;
//        }

//        /// <summary>
//        /// Interpolates an AnimationContent object to 60 fps.
//        /// </summary>
//        /// <param name="input">The AnimationContent to interpolate.</param>
//        /// <returns>The interpolated AnimationContent.</returns>
//        public virtual AnimationInfo Interpolate(AnimationContent input)
//        {
//            long time = 0;
//            long animationDuration = input.Duration.Ticks;

//            /// default XNA importers, due to floating point errors or TimeSpan
//            /// estimation, sometimes  have channels with a duration slightly longer than
//            /// the animation duration.  So, set the animation duration to its true
//            /// value
//            foreach (KeyValuePair<string, AnimationChannel> c in input.Channels)
//            {
//                if (c.Value[c.Value.Count - 1].Time.Ticks > animationDuration)
//                    animationDuration = c.Value[c.Value.Count - 1].Time.Ticks;
//            }

//            Dictionary<string, BoneKeyframeCollection> bonesKeyframes =
//                new Dictionary<string, BoneKeyframeCollection>();

//            foreach (KeyValuePair<string, AnimationChannel> c in input.Channels)
//            {
//                time = 0;
//                string channelName = c.Key;
//                AnimationChannel channel = c.Value;
//                List<BoneKeyframe> boneKeyframes = new List<BoneKeyframe>();

//                int currentFrame = 0;

//                /// Step through time until the time passes the animation duration
//                while (time <= animationDuration)
//                {
//                    BoneKeyframe keyframe;
//                    /// Clamp the time to the duration of the animation and make this 
//                    /// keyframe equal to the last animation frame.
//                    if (time >= animationDuration)
//                    {
//                        time = animationDuration;
//                        keyframe = new BoneKeyframe(channel[channel.Count - 1].Transform, time);
//                    }
//                    else
//                    {
//                        /// If the channel only has one keyframe, set the transform for the current time
//                        /// to that keyframes transform
//                        if (channel.Count == 1 || time < channel[0].Time.Ticks)
//                            keyframe = new BoneKeyframe(channel[0].Transform, time);
//                        /// If the current track duration is less than the animation duration,
//                        /// use the last transform in the track once the time surpasses the duration
//                        else if (channel[channel.Count - 1].Time.Ticks <= time)
//                            keyframe = new BoneKeyframe(channel[channel.Count - 1].Transform, time);
//                        else // proceed as normal
//                        {
//                            // Go to the next frame that is less than the current time
//                            while (channel[currentFrame + 1].Time.Ticks < time)
//                            {
//                                currentFrame++;
//                            }
//                            // Numerator of the interpolation factor
//                            double interpNumerator = (double)(time - channel[currentFrame].Time.Ticks);
//                            // Denominator of the interpolation factor
//                            double interpDenom = (double)(channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks);
//                            // The interpolation factor, or amount to interpolate between the current
//                            // and next frame
//                            double interpAmount = interpNumerator / interpDenom;

//                            // If the frames are roughly 60 frames per second apart, use linear interpolation
//                            if (channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks
//                                <= ContentUtil.TICKS_PER_60FPS * 1.05)
//                            {
//                                keyframe = new BoneKeyframe(
//                                    Matrix.Lerp(
//                                    channel[currentFrame].Transform,
//                                    channel[currentFrame + 1].Transform,
//                                    (float)interpAmount), time);
//                            }
//                            else // else if the transforms between the current frame and the next aren't identical
//                                // decompose the matrix and interpolate the rotation separately
//                                if (channel[currentFrame].Transform != channel[currentFrame + 1].Transform)
//                                {
//                                    keyframe = new BoneKeyframe(
//                                        ContentUtil.SlerpMatrix(
//                                        channel[currentFrame].Transform,
//                                        channel[currentFrame + 1].Transform,
//                                        (float)interpAmount), time);
//                                }
//                                else // Else the adjacent frames have identical transforms and we can use
//                                    // the current frames transform for the current keyframe.
//                                    keyframe = new BoneKeyframe(channel[currentFrame].Transform, time);

//                        }
//                    }
//                    // Add the interpolated keyframe to the new channel.
//                    boneKeyframes.Add(keyframe);
//                    // Step the time forward by 1/60th of a second
//                    time += ContentUtil.TICKS_PER_60FPS;
//                }

//                // Compensate for the time error,(animation duration % TICKS_PER_60FPS),
//                // caused by the interpolation by setting the last keyframe in the
//                // channel to the animation duration.
//                if (boneKeyframes[boneKeyframes.Count - 1].Time < animationDuration)
//                {
//                    boneKeyframes.Add(new BoneKeyframe(
//                        channel[channel.Count - 1].Transform, animationDuration));
//                }

//                boneKeyframes.Add(new BoneKeyframe(
//                    channel[channel.Count - 1].Transform, input.Duration.Ticks));
//                // Add the interpolated channel to the animation

//                BoneKeyframeCollection outChannel =
//                    new BoneKeyframeCollection(channelName, boneKeyframes);

//                bonesKeyframes.Add(c.Key, outChannel);
//            }

//            AnimationInfo output = new AnimationInfo(input.Name, animationDuration,
//                new AnimationChannelCollection(bonesKeyframes));

//            /// Set the interpolated duration to equal the inputs duration for consistency            
//            return output;
//        }
//    }   
//}


